{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c7266ecd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using the Community license in this session. If you have a full Xpress license, first set the XPAUTH_PATH environment variable to the full path to your license file, xpauth.xpr, and then restart Python. If you want to use the FICO Community license and no longer want to see this message, set the XPAUTH_PATH environment variable to: /home/maged/anaconda3/envs/balance/lib/python3.8/site-packages/xpress/license/community-xpauth.xpr\n",
      "NB: setting XPAUTH_PATH will also affect any other Xpress products installed on your system.\n"
     ]
    }
   ],
   "source": [
    "# Importing modules\n",
    "try:\n",
    "    import hsbalance as hs;\n",
    "except ImportError:\n",
    "    !pip install hsbalance\n",
    "    import hsbalance as hs;\n",
    "try:\n",
    "    import matplotlib\n",
    "except ImportError:\n",
    "    !pip install matplotlib\n",
    "    import matplotlib\n",
    "try:\n",
    "    import ipympl\n",
    "except ImportError:\n",
    "    !pip install ipympl\n",
    "    import ipympl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f622ade9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib widget"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1045eff9",
   "metadata": {},
   "source": [
    "# Introduction\n",
    "\n",
    "This notebook is aimed to give a quick presentation for `hsbalance` package.\n",
    "`hsbalance` is Python based package that is meant to find the optimized solution of rotor balancing problem"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce6e51fc",
   "metadata": {},
   "source": [
    "# A. Independent Systems\n",
    "# # Creating Model\n",
    "<b>for independent systems where number of balancing planes are equal to the number of measuring points we do not need optimization process as number of equations are equal to the number of unknowns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9aa04d4f",
   "metadata": {},
   "source": [
    "1. Enter the initial vibration column vector `A`:\n",
    "- each row represents the vibration at certain measuring plane.\n",
    "- vibration is to be represented in the form ('amplitude' @ 'phase(degrees)')\n",
    "- Enter slow roll vibration column `A0`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "120f9d5d",
   "metadata": {},
   "outputs": [],
   "source": [
    "A_math = [['170@112'],\n",
    "     ['53@78']]\n",
    "\n",
    "A0_math = [['12@30'],\n",
    "      ['12@30']]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5c36143",
   "metadata": {},
   "source": [
    "2. Enter trial mass effect matrix `B`\n",
    "B = [['B00', 'B01']\n",
    "     ['B10', 'B11']]\n",
    "where:\n",
    "- B00: vibration at measuring point 1 when trial mass at balancing plane 1\n",
    "- B01: vibration at measuring point 1 when trial mass at balancing plane 2\n",
    "- B00: vibration at measuring point 2 when trial mass at balancing plane 1\n",
    "- B00: vibration at measuring point 2 when trial mass at balancing plane 2\n",
    "\n",
    "As a general rule in this notebook columns will be for balancing planes and rows are for measuring points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "330726b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "B_math = [['235@94', '189@115'],\n",
    "     ['58@68', '77@104']]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0897ea1d",
   "metadata": {},
   "source": [
    "3. Enter the trial mass amounts in row vector `U`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e583d2c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "U_math = ['1.15@0', '1.15@0']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90c543d6",
   "metadata": {},
   "source": [
    "4. Transform matrices to cartesian (complex number) form:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ced90208",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A=\n",
      "[[-63.68312088+157.62125528j]\n",
      " [ 11.01931961 +51.84182284j]]\n",
      "\n",
      "A0=\n",
      "[[10.39230485+6.j]\n",
      " [10.39230485+6.j]]\n",
      "\n",
      "B=\n",
      "[[-16.39277133+234.42755181j -79.87485147+171.29217175j]\n",
      " [ 21.72718242 +53.77666356j -18.62798596 +74.71277092j]]\n",
      "\n",
      "U = [1.15+0.j 1.15+0.j]\n"
     ]
    }
   ],
   "source": [
    "A = hs.convert_matrix_to_cart(A_math)\n",
    "A0 = hs.convert_matrix_to_cart(A0_math)\n",
    "B = hs.convert_matrix_to_cart(B_math)\n",
    "U = hs.convert_matrix_to_cart(U_math)\n",
    "print('A=\\n{}\\n\\nA0=\\n{}\\n\\nB=\\n{}\\n\\nU = {}'.format(A, A0, B, U))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f0e57d4",
   "metadata": {},
   "source": [
    "As in this example, this is an independent system where number of measuring points (M) are equal to the number of balancing planes (N).\n",
    "we, thus, except an exact solution for balancing weights `W` that can be calculated first by find the Influence Coefficients matrix `ALPHA`:\n",
    "\\begin{align}\n",
    "  \\tag {1}\n",
    "  \\alpha = \\frac{(B - A)}{U} \\label{eq:test1}\n",
    "\\end{align}\n",
    "\\begin{align}\n",
    "    \\tag {2}\n",
    "    W = - \\alpha^{-1}(A - A_{0})\n",
    "\\end{align}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "827258e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "Alpha_CI = (B - A)/U\n",
    "W = -np.linalg.inv(Alpha_CI) @ (A - A0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "643ee924",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['78.433 @ 58.4', '18.427 @ 139.8'],\n",
       "       ['9.462 @ 10.2', '32.56 @ 142.4']], dtype='<U14')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(Alpha_CI)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "65bc18c2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.99141015-1.68129487j],\n",
       "       [-0.67544632+0.58516963j]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "W"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c2e6a2c",
   "metadata": {},
   "source": [
    "Transform back to mathematical expression form"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "57a97681",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ALPHA=\n",
      "[['78.433 @ 58.4' '18.427 @ 139.8']\n",
      " ['9.462 @ 10.2' '32.56 @ 142.4']]\n",
      "\n",
      "W=\n",
      "[['1.952 @ 239.5']\n",
      " ['0.894 @ 139.1']]\n"
     ]
    }
   ],
   "source": [
    "ALPHA_math = hs.convert_matrix_to_math(Alpha_CI)\n",
    "W_math = hs.convert_matrix_to_math(W)\n",
    "print('ALPHA=\\n{}\\n\\nW=\\n{}'.format(ALPHA_math, W_math)) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f3007e1",
   "metadata": {},
   "source": [
    ">This means we need to put 2 grams at angel 57.4 degrees on balancing plane 1, and 1.1 grams at 301.1 degrees on plane 2."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b674f5aa",
   "metadata": {},
   "source": [
    "- Lets Try out the same independent system problem using our optimization modeling code:  \n",
    "- first we will create a model of the system parameters:  \n",
    "- we will be using least squares model to solve the problem using optimization technique to minimize the squares of errors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "daabd21c",
   "metadata": {},
   "outputs": [],
   "source": [
    "alpha = hs.Alpha()  # create an instance of alpha class\n",
    "alpha.add(A=A, B=B, U=U)  # calculate alpha from parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ba77b050",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['78.433 @ 58.4', '18.427 @ 139.8'],\n",
       "       ['9.462 @ 10.2', '32.56 @ 142.4']], dtype='<U14')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(alpha.value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a4baf6df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "                Plane 1         Plane 2\n",
      "Sensor 1  78.433 @ 58.4  18.427 @ 139.8\n",
      "Sensor 2   9.462 @ 10.2   32.56 @ 142.4\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Initial Vibration\n",
      "==============================\n",
      "              Vibration\n",
      "Sensor 1  170.0 @ 112.0\n",
      "Sensor 2    53.0 @ 78.0\n",
      "==============================\n",
      "End of Initial Vibration\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Trial Runs Vibration\n",
      "==============================\n",
      "               Plane 1        Plane 2\n",
      "Sensor 1  235.0 @ 94.0  189.0 @ 115.0\n",
      "Sensor 2   58.0 @ 68.0   77.0 @ 104.0\n",
      "==============================\n",
      "End of Trial Runs Vibration\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Trial Masses\n",
      "==============================\n",
      "               Mass\n",
      "Plane 1  1.15 @ 0.0\n",
      "Plane 2  1.15 @ 0.0\n",
      "==============================\n",
      "End of Trial Masses\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "79ed7a35",
   "metadata": {},
   "outputs": [],
   "source": [
    "my_model = hs.LeastSquares(A-A0, alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "7f8aef54",
   "metadata": {},
   "outputs": [],
   "source": [
    "W = my_model.solve()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6a1a2ca0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['1.952 @ 239.5'],\n",
       "       ['0.894 @ 139.1']], dtype='<U13')"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "344a2bd9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_model.rmse()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae22e637",
   "metadata": {},
   "source": [
    "Which is exactly as the exact solution"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ffebd440",
   "metadata": {},
   "source": [
    "In order to summerize the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "197a68bd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL TYPE\n",
      "==================================================\n",
      "LeastSquares\n",
      "==================================================\n",
      "End of MODEL TYPE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INFLUENCE COEFFICIENT MATRIX\n",
      "==================================================\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "                Plane 1         Plane 2\n",
      "Sensor 1  78.433 @ 58.4  18.427 @ 139.8\n",
      "Sensor 2   9.462 @ 10.2   32.56 @ 142.4\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Initial Vibration\n",
      "==============================\n",
      "              Vibration\n",
      "Sensor 1  170.0 @ 112.0\n",
      "Sensor 2    53.0 @ 78.0\n",
      "==============================\n",
      "End of Initial Vibration\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Trial Runs Vibration\n",
      "==============================\n",
      "               Plane 1        Plane 2\n",
      "Sensor 1  235.0 @ 94.0  189.0 @ 115.0\n",
      "Sensor 2   58.0 @ 68.0   77.0 @ 104.0\n",
      "==============================\n",
      "End of Trial Runs Vibration\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Trial Masses\n",
      "==============================\n",
      "               Mass\n",
      "Plane 1  1.15 @ 0.0\n",
      "Plane 2  1.15 @ 0.0\n",
      "==============================\n",
      "End of Trial Masses\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "==================================================\n",
      "End of INFLUENCE COEFFICIENT MATRIX\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INITIAL VIBRATION\n",
      "==================================================\n",
      "                Vibration\n",
      "Sensor 1  168.749 @ 116.0\n",
      "Sensor 2    45.846 @ 89.2\n",
      "==================================================\n",
      "End of INITIAL VIBRATION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "SOLUTION\n",
      "==================================================\n",
      "        Correction Masses\n",
      "Plane 1     1.952 @ 239.5\n",
      "Plane 2     0.894 @ 139.1\n",
      "==================================================\n",
      "End of SOLUTION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "RMSE\n",
      "==================================================\n",
      "0.0\n",
      "==================================================\n",
      "End of RMSE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "Resiudal Vibration Expected\n",
      "==================================================\n",
      "         Expected Vibration\n",
      "Sensor 1          0.0 @ 0.0\n",
      "Sensor 2         0.0 @ 90.0\n",
      "==================================================\n",
      "End of Resiudal Vibration Expected\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(my_model.info())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ecc268f1",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8534d139",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "ac24142c",
   "metadata": {},
   "source": [
    "# A. Dependent Systems\n",
    "## Introduction\n",
    "In dependent systems, number of measuring points are less than the number of balancing planes.  \n",
    "This will lead to a problem with infinite number of solutions as the number of unknowns are less than the number of equations.  \n",
    "We can use optimization technique here effectively to reduce the error and we can apply constraints to our model."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d840eef",
   "metadata": {},
   "source": [
    "We will be example.[[1]](#1) which presents a 1150 MW nuclear power turbine-generator\n",
    "balancing problem. The system consists of 11 measuring points and 5 balancing planes. (independent system)  \n",
    "In practical plane #4 was not accessible.  \n",
    "\n",
    "\n",
    "<a id=\"1\">[1]</a> \n",
    "Gunter, E J, Allaire, P E, and Foiles, W C. Balancing a 1150 MW turbine-generator. United Kingdom: N. p., 2000. Web.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a602bc7e",
   "metadata": {},
   "source": [
    "## Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "f8088da8",
   "metadata": {},
   "outputs": [],
   "source": [
    "ALPHA_math=[\n",
    "                            ['9.8@117', '17@124', '7.2@114', '38.5@77'],\n",
    "                            ['2.7@43', '14.3@317', '4.5@213', '14.3@270'],\n",
    "                            ['12.5@323', '25@261', '15.2@158', '30@238'],\n",
    "                            ['22.4@92', '32.6@45', '23.3@315', '27.8@210'], \n",
    "                            ['26@94', '40.3@9', '25@330', '34@213'],\n",
    "                            ['40.3@355', '43@144', '29.6@61', '65.4@322'],\n",
    "                            ['20.6@339', '32.3@152', '36.7@41', '61.8@322'],\n",
    "                            ['12.6@226', '37.6@52', '18.8@153', '26@176'],\n",
    "                            ['13.4@209', '26.9@76', '47.5@98', '71.7@312'],\n",
    "                            ['13.4@154', '22.4@307', '52@299', '102@165'],\n",
    "                            ['5.4@24', '7.2@199', '22.4@2', '27.8@99']]\n",
    "\n",
    "A_math=[\n",
    "                            ['55@259'], \n",
    "                            ['45@118'],\n",
    "                            ['124@21'],\n",
    "                            ['138@349'],\n",
    "                            ['107@349'],\n",
    "                            ['90@280'],\n",
    "                            ['58@354'],\n",
    "                            ['108@201'],\n",
    "                            ['88@190'],\n",
    "                            ['56@48'],\n",
    "                            ['73@158']]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7144ede",
   "metadata": {},
   "source": [
    "Convert to complex numbers (cartesian) form"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "7933f461",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = hs.convert_matrix_to_cart(A_math)\n",
    "ALPHA = hs.convert_matrix_to_cart(ALPHA_math)\n",
    "# A, ALPHA"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9524b2c9",
   "metadata": {},
   "source": [
    "Adding ALPHA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "eb13e858",
   "metadata": {},
   "outputs": [],
   "source": [
    "alpha = hs.Alpha()\n",
    "alpha.add(direct_matrix=ALPHA)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a41c59f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "Not a square matrix --> no exact solution.\n",
      "\n",
      "No ill conditioned planes --> ok\n"
     ]
    }
   ],
   "source": [
    "alpha.check()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c81228e",
   "metadata": {},
   "source": [
    "## Solving with Least squares:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "6b55e039",
   "metadata": {},
   "outputs": [],
   "source": [
    "model_LeastSquares = hs.LeastSquares(A, alpha, name='Least_squares') # Instantiate least square model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "25d4e6ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_LeastSquares = model_LeastSquares.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "918ed0cd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['3.827 @ 90.7'],\n",
       "       ['2.243 @ 358.4'],\n",
       "       ['1.747 @ 299.3'],\n",
       "       ['1.461 @ 292.5']], dtype='<U13')"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_LeastSquares)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "73f67625",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['19.858 @ 266.8'],\n",
       "       ['37.648 @ 147.4'],\n",
       "       ['106.573 @ 35.2'],\n",
       "       ['59.988 @ 5.1'],\n",
       "       ['63.118 @ 328.9'],\n",
       "       ['39.649 @ 125.6'],\n",
       "       ['58.524 @ 355.2'],\n",
       "       ['67.018 @ 112.2'],\n",
       "       ['51.873 @ 242.4'],\n",
       "       ['33.458 @ 132.4'],\n",
       "       ['46.913 @ 141.6']], dtype='<U14')"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_LeastSquares = model_LeastSquares.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_LeastSquares) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6360299c",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "132aa695",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "53.1472"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_LeastSquares = model_LeastSquares.rmse()\n",
    "rmse_LeastSquares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "226aaea9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL TYPE\n",
      "==================================================\n",
      "LeastSquares\n",
      "==================================================\n",
      "End of MODEL TYPE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL NAME\n",
      "==================================================\n",
      "Least_squares\n",
      "==================================================\n",
      "End of MODEL NAME\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INFLUENCE COEFFICIENT MATRIX\n",
      "==================================================\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "                Plane 1       Plane 2       Plane 3        Plane 4\n",
      "Sensor 1    9.8 @ 117.0  17.0 @ 124.0   7.2 @ 114.0    38.5 @ 77.0\n",
      "Sensor 2     2.7 @ 43.0  14.3 @ 317.0   4.5 @ 213.0   14.3 @ 270.0\n",
      "Sensor 3   12.5 @ 323.0  25.0 @ 261.0  15.2 @ 158.0   30.0 @ 238.0\n",
      "Sensor 4    22.4 @ 92.0   32.6 @ 45.0  23.3 @ 315.0   27.8 @ 210.0\n",
      "Sensor 5    26.0 @ 94.0    40.3 @ 9.0  25.0 @ 330.0   34.0 @ 213.0\n",
      "Sensor 6   40.3 @ 355.0  43.0 @ 144.0   29.6 @ 61.0   65.4 @ 322.0\n",
      "Sensor 7   20.6 @ 339.0  32.3 @ 152.0   36.7 @ 41.0   61.8 @ 322.0\n",
      "Sensor 8   12.6 @ 226.0   37.6 @ 52.0  18.8 @ 153.0   26.0 @ 176.0\n",
      "Sensor 9   13.4 @ 209.0   26.9 @ 76.0   47.5 @ 98.0   71.7 @ 312.0\n",
      "Sensor 10  13.4 @ 154.0  22.4 @ 307.0  52.0 @ 299.0  102.0 @ 165.0\n",
      "Sensor 11    5.4 @ 24.0   7.2 @ 199.0    22.4 @ 2.0    27.8 @ 99.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "==================================================\n",
      "End of INFLUENCE COEFFICIENT MATRIX\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INITIAL VIBRATION\n",
      "==================================================\n",
      "               Vibration\n",
      "Sensor 1    55.0 @ 259.0\n",
      "Sensor 2    45.0 @ 118.0\n",
      "Sensor 3    124.0 @ 21.0\n",
      "Sensor 4   138.0 @ 349.0\n",
      "Sensor 5   107.0 @ 349.0\n",
      "Sensor 6    90.0 @ 280.0\n",
      "Sensor 7    58.0 @ 354.0\n",
      "Sensor 8   108.0 @ 201.0\n",
      "Sensor 9    88.0 @ 190.0\n",
      "Sensor 10    56.0 @ 48.0\n",
      "Sensor 11   73.0 @ 158.0\n",
      "==================================================\n",
      "End of INITIAL VIBRATION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "SOLUTION\n",
      "==================================================\n",
      "        Correction Masses\n",
      "Plane 1      3.827 @ 90.7\n",
      "Plane 2     2.243 @ 358.4\n",
      "Plane 3     1.747 @ 299.3\n",
      "Plane 4     1.461 @ 292.5\n",
      "==================================================\n",
      "End of SOLUTION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "RMSE\n",
      "==================================================\n",
      "53.1472\n",
      "==================================================\n",
      "End of RMSE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "Resiudal Vibration Expected\n",
      "==================================================\n",
      "          Expected Vibration\n",
      "Sensor 1      19.858 @ 266.8\n",
      "Sensor 2      37.648 @ 147.4\n",
      "Sensor 3      106.573 @ 35.2\n",
      "Sensor 4        59.988 @ 5.1\n",
      "Sensor 5      63.118 @ 328.9\n",
      "Sensor 6      39.649 @ 125.6\n",
      "Sensor 7      58.524 @ 355.2\n",
      "Sensor 8      67.018 @ 112.2\n",
      "Sensor 9      51.873 @ 242.4\n",
      "Sensor 10     33.458 @ 132.4\n",
      "Sensor 11     46.913 @ 141.6\n",
      "==================================================\n",
      "End of Resiudal Vibration Expected\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(model_LeastSquares.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03102a20",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "Least square has iterated over to get the minimum squares of errors (hence, the least `RMSE`)  \n",
    "Doing so, it does it blindly so we can see that it add huge amount of weight at plane 1 (3.8 kg!), meanwhile vibration on bearing #3 is expected to be 106 $\\mu$ which is probably an alarm value!!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ad4b4e0",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75f9d9e9",
   "metadata": {},
   "source": [
    "## Solving with MinMax:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "dcefa666",
   "metadata": {},
   "outputs": [],
   "source": [
    "model_MinMax = hs.Min_max(A, alpha, name='MinMax') # Instantiate MinMax model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "62fcb2c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_MinMax = model_MinMax.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "e7e19cea",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['4.423 @ 88.6'],\n",
       "       ['2.892 @ 352.5'],\n",
       "       ['1.537 @ 322.5'],\n",
       "       ['1.91 @ 305.5']], dtype='<U13')"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_MinMax)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "5b7945b7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['10.271 @ 95.7'],\n",
       "       ['31.904 @ 177.5'],\n",
       "       ['69.941 @ 30.1'],\n",
       "       ['69.51 @ 13.7'],\n",
       "       ['69.941 @ 330.6'],\n",
       "       ['69.941 @ 105.2'],\n",
       "       ['69.941 @ 14.9'],\n",
       "       ['69.941 @ 108.8'],\n",
       "       ['69.941 @ 249.7'],\n",
       "       ['52.389 @ 136.6'],\n",
       "       ['69.941 @ 116.7']], dtype='<U14')"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_MinMax = model_MinMax.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_MinMax) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d397fe24",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "6cdb9053",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "59.4235"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_MinMax = model_MinMax.rmse()\n",
    "rmse_MinMax"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "e1418383",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL TYPE\n",
      "==================================================\n",
      "Min_max\n",
      "==================================================\n",
      "End of MODEL TYPE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL NAME\n",
      "==================================================\n",
      "MinMax\n",
      "==================================================\n",
      "End of MODEL NAME\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INFLUENCE COEFFICIENT MATRIX\n",
      "==================================================\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "                Plane 1       Plane 2       Plane 3        Plane 4\n",
      "Sensor 1    9.8 @ 117.0  17.0 @ 124.0   7.2 @ 114.0    38.5 @ 77.0\n",
      "Sensor 2     2.7 @ 43.0  14.3 @ 317.0   4.5 @ 213.0   14.3 @ 270.0\n",
      "Sensor 3   12.5 @ 323.0  25.0 @ 261.0  15.2 @ 158.0   30.0 @ 238.0\n",
      "Sensor 4    22.4 @ 92.0   32.6 @ 45.0  23.3 @ 315.0   27.8 @ 210.0\n",
      "Sensor 5    26.0 @ 94.0    40.3 @ 9.0  25.0 @ 330.0   34.0 @ 213.0\n",
      "Sensor 6   40.3 @ 355.0  43.0 @ 144.0   29.6 @ 61.0   65.4 @ 322.0\n",
      "Sensor 7   20.6 @ 339.0  32.3 @ 152.0   36.7 @ 41.0   61.8 @ 322.0\n",
      "Sensor 8   12.6 @ 226.0   37.6 @ 52.0  18.8 @ 153.0   26.0 @ 176.0\n",
      "Sensor 9   13.4 @ 209.0   26.9 @ 76.0   47.5 @ 98.0   71.7 @ 312.0\n",
      "Sensor 10  13.4 @ 154.0  22.4 @ 307.0  52.0 @ 299.0  102.0 @ 165.0\n",
      "Sensor 11    5.4 @ 24.0   7.2 @ 199.0    22.4 @ 2.0    27.8 @ 99.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "==================================================\n",
      "End of INFLUENCE COEFFICIENT MATRIX\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INITIAL VIBRATION\n",
      "==================================================\n",
      "               Vibration\n",
      "Sensor 1    55.0 @ 259.0\n",
      "Sensor 2    45.0 @ 118.0\n",
      "Sensor 3    124.0 @ 21.0\n",
      "Sensor 4   138.0 @ 349.0\n",
      "Sensor 5   107.0 @ 349.0\n",
      "Sensor 6    90.0 @ 280.0\n",
      "Sensor 7    58.0 @ 354.0\n",
      "Sensor 8   108.0 @ 201.0\n",
      "Sensor 9    88.0 @ 190.0\n",
      "Sensor 10    56.0 @ 48.0\n",
      "Sensor 11   73.0 @ 158.0\n",
      "==================================================\n",
      "End of INITIAL VIBRATION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "SOLUTION\n",
      "==================================================\n",
      "        Correction Masses\n",
      "Plane 1      4.423 @ 88.6\n",
      "Plane 2     2.892 @ 352.5\n",
      "Plane 3     1.537 @ 322.5\n",
      "Plane 4      1.91 @ 305.5\n",
      "==================================================\n",
      "End of SOLUTION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "RMSE\n",
      "==================================================\n",
      "59.4235\n",
      "==================================================\n",
      "End of RMSE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "Resiudal Vibration Expected\n",
      "==================================================\n",
      "          Expected Vibration\n",
      "Sensor 1       10.271 @ 95.7\n",
      "Sensor 2      31.904 @ 177.5\n",
      "Sensor 3       69.941 @ 30.1\n",
      "Sensor 4        69.51 @ 13.7\n",
      "Sensor 5      69.941 @ 330.6\n",
      "Sensor 6      69.941 @ 105.2\n",
      "Sensor 7       69.941 @ 14.9\n",
      "Sensor 8      69.941 @ 108.8\n",
      "Sensor 9      69.941 @ 249.7\n",
      "Sensor 10     52.389 @ 136.6\n",
      "Sensor 11     69.941 @ 116.7\n",
      "==================================================\n",
      "End of Resiudal Vibration Expected\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(model_MinMax.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43b4f866",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "`MinMax` is a great optimization tool that tends to, instead of unbiased `Least Squares`, level up the residuals to minimize the maximum. here we see that we have a great improvement in the residual vibrations (max 70$\\mu\\$).  \n",
    "The downside is putting more and more weights in the correction (4.4 grams in plane 1 now!) and ends up with higher RMSE."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "881bb284",
   "metadata": {},
   "source": [
    "In order to constraint the weight to a certain limit we can perform a Constrained Minmax` model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "598b2eff",
   "metadata": {},
   "outputs": [],
   "source": [
    "weight_const ={0 : 3.402, 1 : 3.402, 2 : 3.402, 3 : 3.402} # limit weight to 120 oz\n",
    "model_MinMax_const = hs.Min_max(A, alpha, weight_const=weight_const, name='MinMax_const') # Instantiate MinMax model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "dadb34a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_MinMax_const = model_MinMax_const.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "d2db52d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['3.402 @ 91.0'],\n",
       "       ['2.322 @ 354.6'],\n",
       "       ['1.363 @ 317.7'],\n",
       "       ['1.778 @ 309.7']], dtype='<U13')"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_MinMax_const)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "341e0587",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['7.447 @ 43.0'],\n",
       "       ['31.72 @ 168.6'],\n",
       "       ['72.931 @ 27.9'],\n",
       "       ['72.931 @ 2.6'],\n",
       "       ['72.931 @ 329.7'],\n",
       "       ['13.579 @ 126.6'],\n",
       "       ['72.931 @ 352.2'],\n",
       "       ['72.931 @ 128.6'],\n",
       "       ['72.931 @ 249.9'],\n",
       "       ['69.667 @ 132.0'],\n",
       "       ['67.667 @ 121.9']], dtype='<U14')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_MinMax_const = model_MinMax_const.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_MinMax_const) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bea604f",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "9a83c1bd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "57.0606"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_MinMax_const = model_MinMax_const.rmse()\n",
    "rmse_MinMax_const"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "657660fa",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "Constrained MinMAx` has done its job in minimizing the weights to 3.402 Kg (120 oz).  \n",
    "The downside is that we got more maximum vibration in residuals (73$\\mu\\$)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "793c9314",
   "metadata": {},
   "source": [
    "## Solving with Linear Matrix Inequality (LMI)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb8b15ae",
   "metadata": {},
   "source": [
    "In certain situations, instead of being unbiased ---> `Least Squares` or leveled ---> `MinMax`, we actually want to be BIASED to certain planes. In other words we want the optimzer to do its best to decrease certain planes (`critical planes`) and keep the others under a `lazy constrains` just below certain amount of vibration level."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "01e03c62",
   "metadata": {},
   "outputs": [],
   "source": [
    "weight_const ={0 : 3.402, 1 : 3.402, 2 : 3.402, 3 : 3.402} # limit weight to 120 oz\n",
    "critical_planes = {1, 9} #  setting the critical planes to be 2, 10 (note python start counting at 0)\n",
    "V_max = 76 # max vibration for non-critical planes\n",
    "model_LMI = hs.LMI(A, alpha, weight_const=weight_const, critical_planes=critical_planes, V_max=V_max\n",
    "                     , name='LMI') # Instantiate LMI model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "9ce46bf7",
   "metadata": {},
   "outputs": [],
   "source": [
    "W_LMI = model_LMI.solve() #solve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "a15bdb69",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['3.402 @ 98.0'],\n",
       "       ['1.951 @ 358.6'],\n",
       "       ['1.298 @ 337.6'],\n",
       "       ['1.605 @ 314.8']], dtype='<U13')"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hs.convert_matrix_to_math(W_LMI)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "89d39c41",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['4.731 @ 224.2'],\n",
       "       ['31.601 @ 163.9'],\n",
       "       ['76.0 @ 29.0'],\n",
       "       ['76.0 @ 350.9'],\n",
       "       ['76.0 @ 325.9'],\n",
       "       ['24.723 @ 129.9'],\n",
       "       ['76.0 @ 7.5'],\n",
       "       ['76.0 @ 145.6'],\n",
       "       ['67.023 @ 237.1'],\n",
       "       ['45.143 @ 123.2'],\n",
       "       ['74.507 @ 120.0']], dtype='<U14')"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "residuals_LMI = model_LMI.expected_residual_vibration()\n",
    "hs.convert_matrix_to_math(residuals_LMI) # Expected residule vibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbb45b9f",
   "metadata": {},
   "source": [
    "Root mean square error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "54b9c35d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "57.0662"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rmse_LMI = model_LMI.rmse()\n",
    "rmse_LMI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "cb3a358b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL TYPE\n",
      "==================================================\n",
      "LMI\n",
      "==================================================\n",
      "End of MODEL TYPE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "MODEL NAME\n",
      "==================================================\n",
      "LMI\n",
      "==================================================\n",
      "End of MODEL NAME\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INFLUENCE COEFFICIENT MATRIX\n",
      "==================================================\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Influence Coefficient Matrix\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "Coefficient Values\n",
      "==============================\n",
      "                Plane 1       Plane 2       Plane 3        Plane 4\n",
      "Sensor 1    9.8 @ 117.0  17.0 @ 124.0   7.2 @ 114.0    38.5 @ 77.0\n",
      "Sensor 2     2.7 @ 43.0  14.3 @ 317.0   4.5 @ 213.0   14.3 @ 270.0\n",
      "Sensor 3   12.5 @ 323.0  25.0 @ 261.0  15.2 @ 158.0   30.0 @ 238.0\n",
      "Sensor 4    22.4 @ 92.0   32.6 @ 45.0  23.3 @ 315.0   27.8 @ 210.0\n",
      "Sensor 5    26.0 @ 94.0    40.3 @ 9.0  25.0 @ 330.0   34.0 @ 213.0\n",
      "Sensor 6   40.3 @ 355.0  43.0 @ 144.0   29.6 @ 61.0   65.4 @ 322.0\n",
      "Sensor 7   20.6 @ 339.0  32.3 @ 152.0   36.7 @ 41.0   61.8 @ 322.0\n",
      "Sensor 8   12.6 @ 226.0   37.6 @ 52.0  18.8 @ 153.0   26.0 @ 176.0\n",
      "Sensor 9   13.4 @ 209.0   26.9 @ 76.0   47.5 @ 98.0   71.7 @ 312.0\n",
      "Sensor 10  13.4 @ 154.0  22.4 @ 307.0  52.0 @ 299.0  102.0 @ 165.0\n",
      "Sensor 11    5.4 @ 24.0   7.2 @ 199.0    22.4 @ 2.0    27.8 @ 99.0\n",
      "==============================\n",
      "End of Coefficient Values\n",
      "++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "==================================================\n",
      "End of INFLUENCE COEFFICIENT MATRIX\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "INITIAL VIBRATION\n",
      "==================================================\n",
      "               Vibration\n",
      "Sensor 1    55.0 @ 259.0\n",
      "Sensor 2    45.0 @ 118.0\n",
      "Sensor 3    124.0 @ 21.0\n",
      "Sensor 4   138.0 @ 349.0\n",
      "Sensor 5   107.0 @ 349.0\n",
      "Sensor 6    90.0 @ 280.0\n",
      "Sensor 7    58.0 @ 354.0\n",
      "Sensor 8   108.0 @ 201.0\n",
      "Sensor 9    88.0 @ 190.0\n",
      "Sensor 10    56.0 @ 48.0\n",
      "Sensor 11   73.0 @ 158.0\n",
      "==================================================\n",
      "End of INITIAL VIBRATION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "SOLUTION\n",
      "==================================================\n",
      "        Correction Masses\n",
      "Plane 1      3.402 @ 98.0\n",
      "Plane 2     1.951 @ 358.6\n",
      "Plane 3     1.298 @ 337.6\n",
      "Plane 4     1.605 @ 314.8\n",
      "==================================================\n",
      "End of SOLUTION\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "RMSE\n",
      "==================================================\n",
      "57.0662\n",
      "==================================================\n",
      "End of RMSE\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "Resiudal Vibration Expected\n",
      "==================================================\n",
      "          Expected Vibration\n",
      "Sensor 1       4.731 @ 224.2\n",
      "Sensor 2      31.601 @ 163.9\n",
      "Sensor 3         76.0 @ 29.0\n",
      "Sensor 4        76.0 @ 350.9\n",
      "Sensor 5        76.0 @ 325.9\n",
      "Sensor 6      24.723 @ 129.9\n",
      "Sensor 7          76.0 @ 7.5\n",
      "Sensor 8        76.0 @ 145.6\n",
      "Sensor 9      67.023 @ 237.1\n",
      "Sensor 10     45.143 @ 123.2\n",
      "Sensor 11     74.507 @ 120.0\n",
      "==================================================\n",
      "End of Resiudal Vibration Expected\n",
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
      "\n",
      "                   \n"
     ]
    }
   ],
   "source": [
    "print(model_LMI.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56e6e085",
   "metadata": {},
   "source": [
    "### Discussion\n",
    "LMI model has been biased to plane 2 with a slight enhancement and plane 10 which greatly decreased from 69.7$\\mu$ to 45.1$\\mu$ (35% decrease) but that was with the cost of increasing non critical planes to the limit we have assigned (76$\\mu\\$)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e62ea916",
   "metadata": {},
   "source": [
    "## Plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "a24c2b00",
   "metadata": {},
   "outputs": [],
   "source": [
    "models = [model_LeastSquares, model_MinMax, model_MinMax_const, model_LMI]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "37f18576",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_models(models):\n",
    "    residule_vibration = {model.name:abs(model.expected_residual_vibration().ravel()) for model in models}\n",
    "    rmse = {model.name:model.rmse() for model in models}\n",
    "    fig, (ax0, ax1) = plt.subplots(2, 1)\n",
    "    ax0.bar(rmse.keys(), rmse.values())\n",
    "    plt.xlabel('Models')\n",
    "    plt.ylabel('Vibration');\n",
    "    models_number = len(residule_vibration.values())\n",
    "    measuring_points = max((len(array) for array in residule_vibration.values()))\n",
    "\n",
    "    jet= plt.get_cmap('jet')\n",
    "    colors = iter(jet(np.linspace(0,1,models_number)))\n",
    "\n",
    "    step = 0\n",
    "    for array in residule_vibration.values():\n",
    "        ax1.bar(np.arange(len(array)) + step, array, color = next(colors), width = 1/models_number)\n",
    "        step += 1 / (models_number+1)\n",
    "    ax1.legend([model.name for model in models])\n",
    "    ax1.set_xticks(range(measuring_points), ['M.P '+ str(point) for point in range(1, 1+measuring_points)],\n",
    "                  rotation =45);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "c91fe026",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "153a1e1188194a6982db5b9cb85de6b4",
       "version_major": 2,
       "version_minor": 0
      },
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAABdSklEQVR4nO3de1zN9+MH8Nfpjm4KJUq5Te6US7K5NbnMMBvzjUVt5hIq15Dkzhja15i2yr5jmbmMGd99F/IdMSKXsdzVlsJSEV3U+/eHX5+voys618/r+XicB+fz+ZzPeZ3P6XRefa4KIYQAEREREcmGgaYDEBEREZF6sQASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyYyRpgPosuLiYqSlpcHCwgIKhULTcYiIiKgKhBB48OABHBwcYGAgz3VhLICvIC0tDY6OjpqOQURERC8hNTUVDRs21HQMjWABfAUWFhYAnv4AWVpaajgNERERVUVOTg4cHR2l73E50usC+Ndff2HWrFnYv38/Hj16hKZNmyI6Ohru7u4Anq4CDgsLQ2RkJLKysuDp6YkNGzagWbNmVZp/yWZfS0tLFkAiIiIdI+fdt/R2w/f9+/fh6ekJY2Nj7N+/HxcvXsTq1atRu3ZtaZqVK1ciIiICGzduxIkTJ1CrVi14e3sjLy9Pg8mJiIiIVEshhBCaDqEKs2fPxtGjR/Hf//63zPFCCDg4OGDatGmYPn06ACA7Oxt2dnaIiYnB+++/X+lz5OTkwMrKCtnZ2VwDSEREpCP4/a3HawD37NkDd3d3vPfee6hXrx46dOiAyMhIafyNGzeQnp4OLy8vaZiVlRW6dOmChISEMueZn5+PnJwcpRsRERGRrtHbAnj9+nVpf75///vfmDBhAqZMmYLNmzcDANLT0wEAdnZ2So+zs7OTxj1v2bJlsLKykm48ApiIiIh0kd4WwOLiYnTs2BFLly5Fhw4dMG7cOHz00UfYuHHjS88zJCQE2dnZ0i01NbUaExMRERGph94eBVy/fn20bNlSaZirqyt27NgBALC3twcAZGRkoH79+tI0GRkZaN++fZnzNDU1hampqWoCk2w4z96n6QiydXP5QE1HICLSCnq7BtDT0xPJyclKwy5fvoxGjRoBAFxcXGBvb4+4uDhpfE5ODk6cOAEPDw+1ZiUiIiJSJ71dAxgUFIRu3bph6dKlGD58OH777Tds2rQJmzZtAvD03D+BgYFYvHgxmjVrBhcXF4SGhsLBwQFDhgzRbHgiIiIiFdLbAtipUyfs2rULISEhWLhwIVxcXLB27Vr4+PhI08ycORO5ubkYN24csrKy0L17dxw4cABmZmYaTE5ERESkWnp7HkB14HmE6GVwH0DN4T6ARATw+xvQ430AiYiIiKhsersJmIhI3bh2V3NUvXaX761mcK296nANIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHMsAASERERyQwLIBEREZHM8EogWoxnntcMnnmeiIj0HdcAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzLAAEhEREckMCyARERGRzMiiAC5fvhwKhQKBgYHSsLy8PEyaNAm2trYwNzfHsGHDkJGRobmQRERERGqi9wXw5MmT+OKLL9C2bVul4UFBQdi7dy+2b9+O+Ph4pKWl4Z133tFQSiIiIiL10esC+PDhQ/j4+CAyMhK1a9eWhmdnZ+Orr77Cp59+it69e8PNzQ3R0dE4duwYjh8/rsHERERERKqn1wVw0qRJGDhwILy8vJSGJyYmorCwUGl4ixYt4OTkhISEBHXHJCIiIlIrI00HUJXY2FicPn0aJ0+eLDUuPT0dJiYmsLa2VhpuZ2eH9PT0cueZn5+P/Px86X5OTk615SUiIiJSF71cA5iamoqpU6diy5YtMDMzq7b5Llu2DFZWVtLN0dGx2uZNREREpC56WQATExNx584ddOzYEUZGRjAyMkJ8fDwiIiJgZGQEOzs7FBQUICsrS+lxGRkZsLe3L3e+ISEhyM7Olm6pqakqfiVERERE1U8vNwH36dMH58+fVxo2duxYtGjRArNmzYKjoyOMjY0RFxeHYcOGAQCSk5ORkpICDw+PcudramoKU1NTlWYnIiIiUjW9LIAWFhZo3bq10rBatWrB1tZWGu7v74/g4GDY2NjA0tISkydPhoeHB7p27aqJyERERERqo5cFsCrWrFkDAwMDDBs2DPn5+fD29sbnn3+u6VhEREREKiebAnj48GGl+2ZmZli/fj3Wr1+vmUBEREREGqKXB4EQERERUflYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGZYAImIiIhkhgWQiIiISGb0tgAuW7YMnTp1goWFBerVq4chQ4YgOTlZaZq8vDxMmjQJtra2MDc3x7Bhw5CRkaGhxERERETqobcFMD4+HpMmTcLx48fxn//8B4WFhejbty9yc3OlaYKCgrB3715s374d8fHxSEtLwzvvvKPB1ERERESqZ6TpAKpy4MABpfsxMTGoV68eEhMT8cYbbyA7OxtfffUVtm7dit69ewMAoqOj4erqiuPHj6Nr166aiE1ERESkcnq7BvB52dnZAAAbGxsAQGJiIgoLC+Hl5SVN06JFCzg5OSEhIUEjGYmIiIjUQW/XAD6ruLgYgYGB8PT0ROvWrQEA6enpMDExgbW1tdK0dnZ2SE9PL3M++fn5yM/Pl+7n5OSoLDMRERGRqshiDeCkSZNw4cIFxMbGvtJ8li1bBisrK+nm6OhYTQmJiIiI1EfvC2BAQAB+/PFHHDp0CA0bNpSG29vbo6CgAFlZWUrTZ2RkwN7evsx5hYSEIDs7W7qlpqaqMjoRERGRSuhtARRCICAgALt27cLBgwfh4uKiNN7NzQ3GxsaIi4uThiUnJyMlJQUeHh5lztPU1BSWlpZKNyIiIiJdo7f7AE6aNAlbt27FDz/8AAsLC2m/PisrK9SoUQNWVlbw9/dHcHAwbGxsYGlpicmTJ8PDw4NHABMREZFe09sCuGHDBgBAz549lYZHR0djzJgxAIA1a9bAwMAAw4YNQ35+Pry9vfH555+rOSkRERGReultARRCVDqNmZkZ1q9fj/Xr16shEREREZF20Nt9AImIiIiobCyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkMyyARERERDLDAkhEREQkM7IvgOvXr4ezszPMzMzQpUsX/Pbbb5qORERERKRSsi6A27ZtQ3BwMMLCwnD69Gm0a9cO3t7euHPnjqajEREREamMrAvgp59+io8+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",
      "text/html": [
       "\n",
       "            <div style=\"display: inline-block;\">\n",
       "                <div class=\"jupyter-widgets widget-label\" style=\"text-align: center;\">\n",
       "                    Figure\n",
       "                </div>\n",
       "                <img src='' width=640.0/>\n",
       "            </div>\n",
       "        "
      ],
      "text/plain": [
       "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_models(models)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb884e52",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fcde27e2",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50450d4e",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d66902f0",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fdc88c0a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d29c5c3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:balance] *",
   "language": "python",
   "name": "conda-env-balance-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
